package com.yuan.security;

import com.yuan.ayuancity.entity.Admins;
import com.yuan.view.JwtHelper;
import com.yuan.view.YuancityView;
import io.jsonwebtoken.Claims;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <p>
 *
 * </p>
 *
 * @author asuyuan
 * @since 2023/3/3
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    //自定义登录拦截，必须配置密码加密的实例
    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder(){
       return new BCryptPasswordEncoder();
    }

    //放行验证码，不走security
    @Override
    public void configure(WebSecurity web) throws Exception{
       web.ignoring().mvcMatchers("/city/v1/getCaptcha");
       web.ignoring().mvcMatchers("/city/v1/SendEmail");
       web.ignoring().mvcMatchers("/city/v1/uploadImage");
       web.ignoring().mvcMatchers("/city/v1/pay/alipay");
       web.ignoring().mvcMatchers("/city/v1/pay/alipay2");
       web.ignoring().mvcMatchers("/city/v1/returnUrl");
       web.ignoring().mvcMatchers("/image/**");
       web.ignoring().mvcMatchers("/view/**/*.*");
       web.ignoring().mvcMatchers("/view/css/pluins/**");
       web.ignoring().mvcMatchers("/view/js/*.*");
       web.ignoring().mvcMatchers("/view/html/*.*");
       // web.ignoring().mvcMatchers("/city/admin/login");
       // web.ignoring().mvcMatchers("/city/admin/info");
       // web.ignoring().mvcMatchers("/city/admin/logout");
    }

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
   //配置登录



    @Override
    public void configure(HttpSecurity http) throws Exception{
         //关闭csrf
        http.csrf().disable();
        //开启跨域
        http.cors();
        //swagger的fram窗口
        http.headers().frameOptions().disable();
        //登录
        http.authorizeRequests()//过滤请求
                //放行
                .antMatchers("/swagger-ui.html", "/webjars/springfox-swagger-ui/**").permitAll()
                .antMatchers("/ayuancity/categorys/**").permitAll()
                .antMatchers("/ayuancity/infos/getHotInfos").permitAll()
                .antMatchers("/ayuancity/front/**","/ayuancity/users/**").permitAll()
                .antMatchers("/ayuancity/infos/**").permitAll()
                .antMatchers("/city/user/**").permitAll()
                .antMatchers("/ayuancity/carts/**").permitAll()
                .antMatchers("/ayuancity/orders/**").permitAll()
                .antMatchers("/ayuancity/comment/**").permitAll()
                .antMatchers("/ayuancity/users/registerUser").permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .formLogin()//登录
                .loginProcessingUrl("/city/admin/login")//请求什么URL时执行登录逻辑
                .successHandler(new AuthenticationSuccessHandler() {
                    //登录成功
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                      //获取当前用户信息
                       SecurityUser details = (SecurityUser)authentication.getPrincipal();
                       //封装JWT
                        JwtHelper jwtHelper=new JwtHelper();
                        String adminToken = jwtHelper.createUserToken(details, new Admins());
                        Claims claimsByToken = jwtHelper.getClaimsByToken(adminToken);
                        System.out.println("管理员token==="+claimsByToken);
                        //封装数据类型
                        YuancityView.success("登录成功")
                                // .put("user", details.getAdmins())
                                .put("token", adminToken)
                                .put("authorities", details.getAuthorities())
                                .responseWebClient(response);
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    //登录失败
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                        //封装数据类型
                        YuancityView.failure("登录失败",411)
                                .put("error", exception.getMessage())
                                .responseWebClient(response);
                    }
                })
                .permitAll()//无条件允许访问
                .and()
                .logout()
                .logoutUrl("/city/admin/logout")//执行什么方法退出
                .invalidateHttpSession(true)//销毁session
                .clearAuthentication(true)//清除认证
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        SecurityUser principal = (SecurityUser)authentication.getPrincipal();
                        YuancityView.success("退出成功")
                                .put("username", principal.getAdmins().getAdminName())
                                .put("token","")
                                .responseWebClient(response);
                    }
                })
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                      YuancityView.failure("没有系统访问权限, 请联系系统管理员...")
                              .responseWebClient(response);
                    }
                })
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                YuancityView.failure("非法访问, 请联系系统管理员...").responseWebClient(response);
            }
        });
        // 添加验证码校验器
        http.addFilterBefore(new VerifyCodeFilter(),
                UsernamePasswordAuthenticationFilter.class);

    }




}
